package com.shycloud.mido.homework.service.impl;

import com.shycloud.mido.member.api.feign.RemoteMemberService;
import com.shycloud.mido.member.api.util.UUIDUtil;
import com.shycloud.mido.member.api.vo.TeacherVO;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.TemporalField;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.JsonObject;
import com.joy.zebra.common.push.JPushUtils;
import com.shycloud.common.minio.service.MinioTemplate;
import com.shycloud.mido.common.api.constants.HomeWorkConstants;
import com.shycloud.mido.common.api.constants.ShoppingStockConstants;
import com.shycloud.mido.common.api.enums.AssignLimitPeriodEnum;
import com.shycloud.mido.common.api.enums.HomeworkStatusEnum;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.security.util.SecurityUtils;
import com.shycloud.mido.common.util.DateUtil;
import com.shycloud.mido.common.util.NetworkUtil;
import com.shycloud.mido.common.util.SnowFlakeUtil;
import com.shycloud.mido.homework.api.dto.AssignDto;
import com.shycloud.mido.homework.api.entity.MidoHomeworkComment;
import com.shycloud.mido.homework.api.entity.MidoHomeworkComplate;
import com.shycloud.mido.homework.api.entity.MidoHomeworkMain;
import com.shycloud.mido.homework.api.entity.OrgRelationshipUnlinkLog;
import com.shycloud.mido.homework.api.entity.StudentPlayData;
import com.shycloud.mido.homework.api.entity.ZebraHomeworkGroup;
import com.shycloud.mido.homework.api.enums.JPushCodeEnum;
import com.shycloud.mido.homework.api.feign.StudentFeignService;
import com.shycloud.mido.homework.api.feign.TeacherFeignService;
import com.shycloud.mido.homework.api.vo.AtvActiveDetailItemVO;
import com.shycloud.mido.homework.api.vo.AtvActiveDetailReqVO;
import com.shycloud.mido.homework.api.vo.AtvScheduleReqVO;
import com.shycloud.mido.homework.api.vo.AtvScheduleVO;
import com.shycloud.mido.homework.api.vo.HomeworkDashboardReqVO;
import com.shycloud.mido.homework.api.vo.HomeworkDashboardRespVO;
import com.shycloud.mido.homework.api.vo.MidoHomeworkMainVO;
import com.shycloud.mido.homework.api.vo.MusicNameVO;
import com.shycloud.mido.homework.api.vo.PlayDataVO;
import com.shycloud.mido.homework.api.vo.StudentPlayDataVO;
import com.shycloud.mido.homework.config.PropertiesConfig;
import com.shycloud.mido.homework.mapper.MidoHomeworkCommentMapper;
import com.shycloud.mido.homework.mapper.MidoHomeworkComplateMapper;
import com.shycloud.mido.homework.mapper.MidoHomeworkMainMapper;
import com.shycloud.mido.homework.mapper.MidoHomeworkPlayDataMapper;
import com.shycloud.mido.homework.mapper.ZebraHomeworkGroupMapper;
import com.shycloud.mido.homework.service.MidoHomeworkMainService;
import com.shycloud.mido.homework.thread.HomeworkStatusThread;
import com.shycloud.mido.homework.thread.HomeworkStatusThreadV2;
import com.shycloud.mido.member.api.entity.MsgMemberInfo;
import com.shycloud.mido.member.api.feign.RemotePushService;
import cn.hutool.core.map.MapUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * 作业模块业务实现类
 *
 * @author nianhua.jiang
 * @date 2020/6/24 10:50
 */
@Slf4j
@Service
@AllArgsConstructor
public class MidoHomeworkMainServiceImpl extends ServiceImpl<MidoHomeworkMainMapper, MidoHomeworkMain> implements
		MidoHomeworkMainService {

	/** 作业模块 mapper */
	private final MidoHomeworkMainMapper mainMapper;
	/** 作业完成情况 mapper */
	private final MidoHomeworkComplateMapper complateMapper;
	/** 作业评论 mapper */
	private final MidoHomeworkCommentMapper commentMapper;
	/** 作业弹奏数据 */
	private final MidoHomeworkPlayDataMapper playDataMapper;
	/** 教师Feign服务 */
	private final TeacherFeignService teacherFeignService;
	/** 学生Feign服务 */
	private final StudentFeignService studentFeignService;
	/** 参数 */
	private final PropertiesConfig propertiesConfig;
	/** 七牛云参数 */
	private final MinioTemplate minioTemplate;
	/** 下发作业组 */
	private final ZebraHomeworkGroupMapper zebraHomeworkGroupMapper;
	/** 消息推送模块 feign */
	private final RemotePushService remotePushService;
	/** 用户模块 feign */
	private final RemoteMemberService remoteMemberService;

	/**
	 * 下发作业
	 *
	 * @param assignDto 下发作业信息
	 * @return java.lang.Boolean
	 * @author nianhua.jiang
	 * @date 2020/6/24 10:55
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public R<Boolean> assign(AssignDto assignDto) {
		try {
			//保存作业组信息
			//设置分组，用于区分作业
			Integer machineId = ShoppingStockConstants.getConsistentHash(NetworkUtil.getHostIp());
			long groupId = new SnowFlakeUtil(1, machineId).nextId();

			ZebraHomeworkGroup zebraHomeworkGroup = new ZebraHomeworkGroup();
			BeanUtils.copyProperties(assignDto, zebraHomeworkGroup);
			List<String> studentList = assignDto.getStudentList();

			if (CollectionUtils.isNotEmpty(studentList)) {
				zebraHomeworkGroup.setStudentCount(studentList.size());
			}

			zebraHomeworkGroup.setId(groupId);
			zebraHomeworkGroup.setDelFlag("0");
			zebraHomeworkGroup.setCreateTime(LocalDateTime.now());
			zebraHomeworkGroup.setCreateUser(SecurityUtils.getMember().getId());
			zebraHomeworkGroup.setUpdateTime(LocalDateTime.now());
			zebraHomeworkGroup.setUpdateUser(SecurityUtils.getMember().getId());
			zebraHomeworkGroup.setStartDate(assignDto.getStartDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
			zebraHomeworkGroup.setEndDate(assignDto.getEndDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
			zebraHomeworkGroupMapper.insert(zebraHomeworkGroup);

			consumeAssign(assignDto);

			Date startTime = assignDto.getStartDate();
			Date endTime = assignDto.getEndDate();
			Instant inst1 = Instant.ofEpochMilli(startTime.getTime());
			Instant inst2 = Instant.ofEpochMilli(endTime.getTime());
			Long seconds = Duration.between(inst1, inst2).getSeconds();
			Long days = seconds / (24 * 60 * 60);
			Instant temp = inst1;
			Date tempDate = new Date(temp.toEpochMilli());

			//识谱模式【（识谱末次分数-识谱首次次分数）/（识谱次数-1）】
			Integer type2Offset = 0;
			//识谱目标分数
			Integer type2Tatget = 0;

			if (days.intValue() > 0 && assignDto.getTypeTwoNum() > 0) {
				//设置每次作业的步长 - （首次是60分，末次是100分，下发5天作业，则每天作业目标分数为：60 70 80 90 100，步长为 10）
				type2Offset = (assignDto.getTypeTwoEndScore() - assignDto.getTypeTwoStartScore()) / (days.intValue());
				//目标分数取首次分数
				type2Tatget = assignDto.getTypeTwoStartScore();
			}

			//纠错模式 -> 设置初始步长为 0
			Integer type3Offset = 0;
			//目标分数
			Integer type3Tatget = 0;

			if (days.intValue() > 0 && assignDto.getTypeThreeNum() > 0) {
				type3Offset =
						(assignDto.getTypeThreeEndScore() - assignDto.getTypeThreeStartScore())
								/ (days.intValue());
				//目标分数取首次分数
				type3Tatget = assignDto.getTypeThreeStartScore();
			}

			for (int i = 0; i < (days.intValue() + 1); i++) {

				for (String studentId : assignDto.getStudentList()) {

					//视听模式
					MidoHomeworkMain lookAndSoundModel = new MidoHomeworkMain();
					BeanUtils.copyProperties(assignDto, lookAndSoundModel);

					// 试听模式
					if (assignDto.getTypeOneNum() > 0) {

						//弹奏模式(0-视听,1-识谱,2-纠错)
						lookAndSoundModel.setPlayingMode("0");
						//开始日期
						lookAndSoundModel.setStartDate(tempDate);
						//学生ID
						lookAndSoundModel.setStudentId(studentId);
						//创建时间
						lookAndSoundModel.setCreateTime(new Date());
						//视听次数
						lookAndSoundModel.setTargetScore(assignDto.getTypeOneNum());
						//作业分组ID
						lookAndSoundModel.setGroupId(groupId);
						//新增试听模式作业
						mainMapper.insert(lookAndSoundModel);

					}

					if (assignDto.getTypeTwoNum() > 0) {

						for (int j = 0; j < assignDto.getTypeTwoNum(); j++) {

							MidoHomeworkMain mode2 = new MidoHomeworkMain();
							BeanUtils.copyProperties(assignDto, mode2);
							mode2.setPlayingMode("1");
							mode2.setStartDate(tempDate);
							mode2.setStudentId(studentId);
							mode2.setCreateTime(new Date());
							//目标分数
							mode2.setTargetScore(type2Tatget);

							if (i == days.intValue()) {
								mode2.setTargetScore(assignDto.getTypeTwoEndScore());
							}
							//作业分组ID
							mode2.setGroupId(groupId);
							//新增识谱模式作业
							mainMapper.insert(mode2);
						}
					}

					//纠错作业不留
					if (assignDto.getTypeThreeNum() == 0) {

					} else {

						for (int j = 0; j < assignDto.getTypeThreeNum(); j++) {
							MidoHomeworkMain mode3 = new MidoHomeworkMain();
							BeanUtils.copyProperties(assignDto, mode3);
							mode3.setPlayingMode("2");
							mode3.setStartDate(tempDate);
							mode3.setStudentId(studentId);
							mode3.setCreateTime(new Date());
							mode3.setTargetScore(type3Tatget);
							if (i == days.intValue()) {
								mode3.setTargetScore(assignDto.getTypeThreeEndScore());
							}
							//作业分组ID
							mode3.setGroupId(groupId);
							mainMapper.insert(mode3);
						}
					}
				}
				//最后递增时间
				//下次分数 = 本次分数 + 步长
				type2Tatget += type2Offset;
				//目标分数每次呈线性增长
				type3Tatget += type3Offset;
				temp = temp.plus(Duration.ofDays(1));
				tempDate = new Date(temp.toEpochMilli());

			}

			//极光推送ID集合
			List<String> regIds = new ArrayList<>();
			for (String studentId : studentList) {
				//获取regId
				String regIdByStudentId = mainMapper.getRegIdByStudentId(studentId);
				if (StringUtils.isNotEmpty(regIdByStudentId)) {
					regIds.add(regIdByStudentId);
				}
				String memberId = mainMapper.getMemberIdByStudentId(studentId);
				//发送消息
				MsgMemberInfo msgMemberInfo = new MsgMemberInfo();
				msgMemberInfo.setMsgId("homework_assign");
				msgMemberInfo.setFromId("sys");
				msgMemberInfo.setToId(memberId);
				msgMemberInfo.setCreateTime(LocalDateTime.now());
				msgMemberInfo.setDelFlag(CommonConstants.STATUS_NORMAL);

				//classRoomId 查询此教师和学生是否是个人师生关系
				String teacherId = assignDto.getTeacherId();

				//构建推送响应体
				JsonObject jsonObject = new JsonObject();
				//获取教师信息
				TeacherVO teacherVO = remoteMemberService.getTeacherInfoFeign(teacherId);
				//学生头像
				jsonObject.addProperty("teacherHeader", teacherVO.getAvatar());

				jsonObject.addProperty("teacherImId", teacherVO.getImId());

				jsonObject.addProperty("teacherMemberShowName", teacherVO.getTeacherMemberShowName());

				String classroomId = remoteMemberService.getClassroomId(teacherId, studentId);
				//教师ID
				jsonObject.addProperty("teacherId", teacherId);
				//班级ID
				jsonObject.addProperty("classroomId", classroomId);
				//作业时间
				SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
				jsonObject.addProperty("startDate", simpleDateFormat.format(assignDto.getStartDate()));

				msgMemberInfo.setHomeworkData(jsonObject.toString());

				remotePushService.sendMsg(msgMemberInfo);
			}
			//推送
			if (regIds != null && regIds.size() > 0) {
				JPushUtils.sendJPush("收到新作业", "已收到老师布置的作业，快去完成吧", regIds);
				JPushUtils.sendJMessage(JPushCodeEnum.J_PUSH_APP_HOMEPAGE_VIEW.getType(), regIds,
						"通知APP请求 getMsgApp 接口");
				//遍历日期
				ArrayList<String> dateList = new ArrayList<>();
				long distance = ChronoUnit.DAYS.between(zebraHomeworkGroup.getStartDate(), zebraHomeworkGroup.getEndDate());
				if (distance >= 0) {
					Stream.iterate(zebraHomeworkGroup.getStartDate(), day -> {
						return day.plusDays(1);
					}).limit(distance + 1).forEach(item -> {
						dateList.add(DateTimeFormatter.ofPattern("yyyy-MM-dd").format(item));
					});
					JsonObject jsonObject = new JsonObject();
					jsonObject.addProperty(String.valueOf(groupId),
							dateList.stream().map(String::valueOf).collect(Collectors.joining(",")));
					// 推送隐式消息显示红点
					JPushUtils.sendJMessage(JPushCodeEnum.J_PUSH_TEACHER_ASSIGN_HOMEWORK.getType(), regIds, jsonObject);
				}
			}

		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			return new R<>(CommonConstants.FAIL, e.getMessage(), false);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return new R<>(CommonConstants.FAIL, "下发失败", false);
		}

		return new R<>(CommonConstants.SUCCESS, "下发成功", true);
	}


	/**
	 * 家长模式下发作业
	 *
	 * @param assignDto
	 * @return java.lang.Boolean
	 * @author nianhua.jiang
	 * @date 2020/8/24 10:35
	 **/
	@Override
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public R assignForParent(AssignDto assignDto) {
		try {

			//保存作业组信息
			//设置分组，用于区分作业
			//设置分组，用于区分作业 
			Integer machineId = ShoppingStockConstants.getConsistentHash(NetworkUtil.getHostIp());
			long groupId = new SnowFlakeUtil(1, machineId).nextId();

			ZebraHomeworkGroup zebraHomeworkGroup = new ZebraHomeworkGroup();
			BeanUtils.copyProperties(assignDto, zebraHomeworkGroup);
			List<String> studentList = assignDto.getStudentList();
			if (CollectionUtils.isNotEmpty(studentList)) {
				zebraHomeworkGroup.setStudentCount(studentList.size());
			}
			zebraHomeworkGroup.setId(groupId);
			zebraHomeworkGroup.setDelFlag("0");
			zebraHomeworkGroup.setCreateTime(LocalDateTime.now());
			zebraHomeworkGroup.setCreateUser(SecurityUtils.getMember().getId());
			zebraHomeworkGroup.setUpdateTime(LocalDateTime.now());
			zebraHomeworkGroup.setUpdateUser(SecurityUtils.getMember().getId());
			zebraHomeworkGroup.setStartDate(
					assignDto.getStartDate().toInstant().atZone(ZoneId.systemDefault())
							.toLocalDate());
			zebraHomeworkGroup.setEndDate(
					assignDto.getEndDate().toInstant().atZone(ZoneId.systemDefault())
							.toLocalDate());
			zebraHomeworkGroupMapper.insert(zebraHomeworkGroup);

			consumeAssign(assignDto);

			//处理时间
			assignDto.getStartDate();
			assignDto.getEndDate();
			Instant inst1 = Instant.ofEpochMilli(assignDto.getStartDate().getTime());
			Instant inst2 = Instant.ofEpochMilli(assignDto.getEndDate().getTime());
			Long seconds = Duration.between(inst1, inst2).getSeconds();
			Long days = seconds / (24 * 60 * 60);
			Instant temp = inst1;
			Date tempDate = new Date(temp.toEpochMilli());

			//识谱模式【（识谱末次分数-识谱首次次分数）/（识谱次数-1）】
			Integer type2Offset = 0;
			//识谱目标分数
			Integer type2Tatget = 0;

			if (days.intValue() > 0) {
				//设置每次作业的步长 - （首次是60分，末次是100分，下发5天作业，则每天作业目标分数为：60 70 80 90 100，步长为 10）
				type2Offset =
						(assignDto.getTypeTwoEndScore() - assignDto.getTypeTwoStartScore()) / (days
								.intValue());
				//目标分数取首次分数
				type2Tatget = assignDto.getTypeTwoStartScore();
			}

			//纠错模式 -> 设置初始步长为 0
			Integer type3Offset = 0;
			//目标分数
			Integer type3Tatget = 0;

			if (days.intValue() > 0) {
				type3Offset =
						(assignDto.getTypeThreeEndScore() - assignDto.getTypeThreeStartScore())
								/ (days.intValue());
				//目标分数取首次分数
				type3Tatget = assignDto.getTypeThreeStartScore();
			}

			for (int i = 0; i < (days.intValue() + 1); i++) {

				//视听模式
				MidoHomeworkMain lookAndSoundModel = new MidoHomeworkMain();
				BeanUtils.copyProperties(assignDto, lookAndSoundModel);

				if (assignDto.getTypeOneNum() > 0) {
					//弹奏模式(0-视听,1-识谱,2-纠错)
					lookAndSoundModel.setPlayingMode("0");
					//开始日期
					lookAndSoundModel.setStartDate(tempDate);
					//是否是家长模式
					lookAndSoundModel.setIsParentMode("1");
					//教师ID
					lookAndSoundModel.setTeacherId("parentMode");
					//创建时间
					lookAndSoundModel.setCreateTime(new Date());
					//视听次数
					lookAndSoundModel.setTargetScore(assignDto.getTypeOneNum());
					//作业分组ID
					lookAndSoundModel.setGroupId(groupId);
					//新增试听模式作业
					mainMapper.insert(lookAndSoundModel);
				}

				if (assignDto.getTypeTwoNum() > 0) {

					for (int j = 0; j < assignDto.getTypeTwoNum(); j++) {
						MidoHomeworkMain mode2 = new MidoHomeworkMain();
						BeanUtils.copyProperties(assignDto, mode2);
						mode2.setPlayingMode("1");
						mode2.setStartDate(tempDate);
						mode2.setTeacherId("parentMode");
						mode2.setIsParentMode("1");
						mode2.setCreateTime(new Date());
						//目标分数
						mode2.setTargetScore(type2Tatget);
						//作业分组ID
						mode2.setGroupId(groupId);
						if (i == days.intValue()) {
							mode2.setTargetScore(assignDto.getTypeTwoEndScore());
						}

						//新增识谱模式作业
						mainMapper.insert(mode2);
					}
				}

				//纠错作业不留
				if (assignDto.getTypeThreeNum() == 0) {

				} else {

					for (int j = 0; j < assignDto.getTypeThreeNum(); j++) {
						MidoHomeworkMain mode3 = new MidoHomeworkMain();
						BeanUtils.copyProperties(assignDto, mode3);
						mode3.setPlayingMode("2");
						mode3.setStartDate(tempDate);
						mode3.setTeacherId("parentMode");
						mode3.setIsParentMode("1");
						mode3.setCreateTime(new Date());
						mode3.setTargetScore(type3Tatget);
						//作业分组ID
						mode3.setGroupId(groupId);
						if (i == days.intValue()) {
							mode3.setTargetScore(assignDto.getTypeThreeEndScore());
						}
						mainMapper.insert(mode3);
					}
				}

				//最后递增时间
				//下次分数 = 本次分数 + 步长
				type2Tatget += type2Offset;
				//目标分数每次呈线性增长
				type3Tatget += type3Offset;
				temp = temp.plus(Duration.ofDays(1));
				tempDate = new Date(temp.toEpochMilli());
			}
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			return new R(CommonConstants.FAIL, e.getMessage(), false);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return new R(CommonConstants.FAIL, "下发失败", false);
		}

		return new R(CommonConstants.SUCCESS, "下发成功", true);
	}

	@Override
	public Boolean uploadPlayData(PlayDataVO playDataVO, String memberId) {
		if (playDataVO.getGrade() == null) {
			throw new BusinessException("分数不能为空");
		}

		StudentPlayData existingPlayData = playDataMapper
				.selectOne(new QueryWrapper<StudentPlayData>()
						.eq("member_id", memberId)
						.eq("complate_id", playDataVO.getComplateId()));

		StudentPlayData entity = new StudentPlayData();
		entity.setMusicId(playDataVO.getMusicId());
		entity.setType(playDataVO.getType());
		entity.setStudentId(playDataVO.getStudentId());
		entity.setMemberId(memberId);
		entity.setComplateId(playDataVO.getComplateId());
		entity.setHomeworkId(playDataVO.getHomeworkId());

		//同一homeworkId的作业分数高的覆盖弹奏数据和分数
		if (existingPlayData != null) {
			if (playDataVO.getGrade() >= existingPlayData.getGrade()) {
				//将 playData 数据上传到七牛云中
				String playData = playDataVO.getPlayData();
				byte[] bytes = playData.getBytes();
				String url = minioTemplate.uploadByte(bytes, UUIDUtil.getUUID32() + ".json", "zebra-homework-play-data",
						"http://playdata.joymido.com");
				entity.setPlayDataUrl(url);
				entity.setId(existingPlayData.getId());
				entity.setGrade(playDataVO.getGrade());
				entity.setUpdateTime(LocalDateTime.now());
				//entity.setPlayData(playDataVO.getPlayData());
				return playDataMapper.updateById(entity) == 1;
			} else {
				//不更新
				return true;
			}
		} else {

			//将 playData 数据上传到七牛云中
			String playData = playDataVO.getPlayData();
			byte[] bytes = playData.getBytes();
			String url = minioTemplate.uploadByte(bytes, UUIDUtil.getUUID32() + ".json", "zebra-homework-play-data",
					"http://playdata.joymido.com");

			entity.setPlayDataUrl(url);
			//entity.setPlayData(playDataVO.getPlayData());
			entity.setGrade(playDataVO.getGrade());
			entity.setCreateTime(LocalDateTime.now());
			entity.setUpdateTime(LocalDateTime.now());
			playDataMapper.insert(entity);

			return true;
		}
	}

	@Override
	public StudentPlayDataVO getPlayData(String homeworkId) {

		List<StudentPlayDataVO> studentPlayDataVOs = playDataMapper.getPlayDataByHomeworkId(homeworkId);
		if (studentPlayDataVOs != null && studentPlayDataVOs.size() > 0) {
			StudentPlayDataVO studentPlayDataVO = studentPlayDataVOs.get(0);
			//加token
			if (StringUtils.isNotEmpty(studentPlayDataVO.getRecordingSrc())) {
				studentPlayDataVO.setRecordingSrc(
						minioTemplate.getPrivateDownloadUrl(studentPlayDataVO.getRecordingSrc()));
			}
			return studentPlayDataVO;
		} else {
			throw new BusinessException("作业参数错误");
		}
	}

	@Override
	public R getHomework7Days(String startDate, String studentId, boolean isStudent) {

		Map<LocalDate, String> resultMap = MapUtil.newHashMap();

		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(startDate, dateTimeFormatter);

		if ("-1".equals(studentId)) {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			studentId = studentFeignService.getStudentId(memberId);
		}

		int weekValue = date.getDayOfWeek().getValue();

		//计算每周开始日期
		LocalDate startdate = date.plusDays(-1 * weekValue);

		//如果为周末
		if (weekValue == 7) {
			startdate = date;
		}

		tag:
		for (int i = 0; i < 7; i++) {
			//查询当天作业完成情况
			List<String> statusList = new ArrayList<>();
			//查询当天是否有被提醒
			List<String> dingString = new ArrayList<>();

			//家长模式作业
			if (!isStudent) {
				statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
						HomeWorkConstants.PARENT_MODE_TEACHER_ID));
				dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
						HomeWorkConstants.PARENT_MODE_TEACHER_ID));
			}

			if (isStudent) {
				List<String> teacherIdList = teacherFeignService
						.getTeacherIdsByStudentId(studentId);
				//选取之前解绑的老师记录
				List<OrgRelationshipUnlinkLog> unlinkTeacherLogs = teacherFeignService
						.getUniqueTeacherUnlinkLog(studentId);

				if (unlinkTeacherLogs != null && unlinkTeacherLogs.size() != 0) {
					for (OrgRelationshipUnlinkLog log : unlinkTeacherLogs) {
						statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
								log.getTeacherId()));
						dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
								log.getTeacherId()));
					}
				}

				if (teacherIdList != null && teacherIdList.size() != 0) {
					for (int j = 0; j < teacherIdList.size(); j++) {
						statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
								teacherIdList.get(j)));
						dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
								teacherIdList.get(j)));
					}
				}
			} else {
				statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
						teacherFeignService.getCurTeacherIdByStu(studentId)));
				//System.out.println("当天日期===================" + startdate.plusDays(i));
				dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
						teacherFeignService.getCurTeacherIdByStu(studentId)));
			}

			Boolean dingFlg = false;

			if (dingString.contains("1")) {
				dingFlg = true;
			}

			int allNO = 0;
			int allOk = 0;

			//没有作业
			if (statusList.size() == 0 || statusList == null) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.NO_HOMEWORK.getCode());
				continue tag;
			}

			//循环判断状态
			for (String status : statusList) {
				//作业状态(0-未开始,1-未完成,2-已完成)
				if (HomeWorkConstants.NOT_STARTED.equals(status) || HomeWorkConstants.UNFINISHED
						.equals(status)) {
					allNO++;
				}

				if (HomeWorkConstants.COMPELTED.equals(status)) {
					allOk++;
				}
			}

			//全没完成
			if (allNO == statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.ALL_UNFINISHED.getCode());
			}

			//全没完成并且提醒了
			if (allNO == statusList.size() && dingFlg) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.SUCCESS.getCode());
			}

			//全部完成
			if (allOk == statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.ALL_FINISHED.getCode());
			}

			//一半一半
			if (allNO != statusList.size() && allOk != statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.HALF_FINISHED.getCode());
			}

			//一半一半 并且提醒了
			if (allNO != statusList.size() && allOk != statusList.size() && dingFlg) {
				resultMap.put(startdate.plusDays(i),
						HomeworkStatusEnum.HALF_FINISHED_REMINDED.getCode());
			}
		}
		return new R(resultMap);
	}

	@Override
	public R getHomeworkMonth(String startDate, String studentId, boolean isStudent,
			String isParentMode) {

		Map<LocalDate, String> resultMap = MapUtil.newHashMap();

		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(startDate, dateTimeFormatter);

		if ("-1".equals(studentId)) {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			studentId = studentFeignService.getStudentId(memberId);
		}

		Month month = date.getMonth();

		//本月有多少天
		int monthValueCount = date.withMonth(month.getValue()).lengthOfMonth();

		//每月开始日期
		LocalDate startdate = date.with(TemporalAdjusters.firstDayOfMonth()).minusDays(7);

		tag:
		for (int i = 0; i < (7 + monthValueCount + 7); i++) {

			//查询当天作业完成情况
			List<String> statusList = new ArrayList<>();
			//查询当天是否有被提醒
			List<String> dingString = new ArrayList<>();

			//目标
			if ("1".equals(isParentMode)) {
				//家长模式作业
				statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
						HomeWorkConstants.PARENT_MODE_TEACHER_ID));
				dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
						HomeWorkConstants.PARENT_MODE_TEACHER_ID));
			} else {
				if (isStudent) {
					List<String> teacherIdList = teacherFeignService
							.getTeacherIdsByStudentId(studentId);
					//选取之前解绑的老师记录
					List<OrgRelationshipUnlinkLog> unlinkTeacherLogs = teacherFeignService
							.getUniqueTeacherUnlinkLog(studentId);

					if (unlinkTeacherLogs != null && unlinkTeacherLogs.size() != 0) {
						for (OrgRelationshipUnlinkLog log : unlinkTeacherLogs) {
							statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
									log.getTeacherId()));
							dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
									log.getTeacherId()));
						}
					}

					if (teacherIdList != null && teacherIdList.size() != 0) {
						for (int j = 0; j < teacherIdList.size(); j++) {
							statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
									teacherIdList.get(j)));
							dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
									teacherIdList.get(j)));
						}
					}
				} else {
					statusList.addAll(getHomeWorkStatus(startdate.plusDays(i), studentId,
							teacherFeignService.getCurTeacherIdByStu(studentId)));
					//System.out.println("当天日期===================" + startdate.plusDays(i));
					dingString.addAll(getHomeWorkDing(startdate.plusDays(i), studentId,
							teacherFeignService.getCurTeacherIdByStu(studentId)));
				}
			}

			Boolean dingFlg = false;

			if (dingString.contains("1")) {
				dingFlg = true;
			}

			int allNO = 0;
			int allOk = 0;

			//没有作业
			if (statusList.size() == 0 || statusList == null) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.NO_HOMEWORK.getCode());
				continue tag;
			}

			//循环判断状态
			for (String status : statusList) {
				//作业状态(0-未开始,1-未完成,2-已完成)
				if (HomeWorkConstants.NOT_STARTED.equals(status) || HomeWorkConstants.UNFINISHED
						.equals(status)) {
					allNO++;
				}

				if (HomeWorkConstants.COMPELTED.equals(status)) {
					allOk++;
				}
			}

			//全没完成
			if (allNO == statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.ALL_UNFINISHED.getCode());
			}

			//全没完成并且提醒了
			if (allNO == statusList.size() && dingFlg) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.SUCCESS.getCode());
			}

			//全部完成
			if (allOk == statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.ALL_FINISHED.getCode());
			}

			//一半一半
			if (allNO != statusList.size() && allOk != statusList.size()) {
				resultMap.put(startdate.plusDays(i), HomeworkStatusEnum.HALF_FINISHED.getCode());
			}

			//一半一半 并且提醒了
			if (allNO != statusList.size() && allOk != statusList.size() && dingFlg) {
				resultMap.put(startdate.plusDays(i),
						HomeworkStatusEnum.HALF_FINISHED_REMINDED.getCode());
			}
		}
		return new R(resultMap);
	}

	@Override
	public R getHomeworkMonthByThread(String startDate, String studentId, boolean isStudent,
			String isParentMode) throws Exception {

		Map<LocalDate, String> resultMap = new ConcurrentHashMap<LocalDate, String>();

		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(startDate, dateTimeFormatter);

		if ("-1".equals(studentId)) {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			studentId = studentFeignService.getStudentId(memberId);
		}

		Month month = date.getMonth();

		//本月有多少天
		int monthValueCount = date.withMonth(month.getValue()).lengthOfMonth();

		//每月开始日期
		LocalDate startdate = date.with(TemporalAdjusters.firstDayOfMonth()).minusDays(7);

		//查询天数
		int dayCount = 7 + monthValueCount + 7;

		int thresholdCount = 8;

		Semaphore semaphore = new Semaphore(thresholdCount);
		CountDownLatch countDownLatch = new CountDownLatch(dayCount);

		String curTeacherIdByStu = teacherFeignService.getCurTeacherIdByStu(studentId);

		for (int i = 0; i < dayCount; i++) {
			LocalDate indexDate = startdate.plusDays(i);
			HomeworkStatusThread homeworkStatusJob =
					new HomeworkStatusThread(indexDate, studentId, isParentMode, isStudent,
							curTeacherIdByStu, resultMap, semaphore, countDownLatch);
			new Thread(homeworkStatusJob).start();
		}
		countDownLatch.await();

		return new R(resultMap);
	}

	@Override
	public R<Map<LocalDate, HomeworkDashboardRespVO>> getHomeworkMonthByThreadV2(HomeworkDashboardReqVO vo) throws Exception {

		String startDate = vo.getCurrentViewDay();
		String studentId = vo.getStudentId();

		Map<LocalDate, HomeworkDashboardRespVO> resultMap = new ConcurrentHashMap<LocalDate, HomeworkDashboardRespVO>();

		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(startDate, dateTimeFormatter);

		if ("-1".equals(studentId)) {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			studentId = studentFeignService.getStudentId(memberId);
		}
		String viewType = vo.getViewType();
		int dayCount = 0;
		LocalDate startdate = LocalDate.now();
		if (StringUtils.equals("1", viewType)) {
			Month month = date.getMonth();
			//本月有多少天
			int monthValueCount = date.withMonth(month.getValue()).lengthOfMonth();
			//每月开始日期
			startdate = date.with(TemporalAdjusters.firstDayOfMonth()).minusDays(7);
			//查询天数
			dayCount = 7 + monthValueCount + 7;
		} else {
			TemporalField fieldISO = WeekFields.of(DayOfWeek.MONDAY, 1).dayOfWeek();
			LocalDate localDate = LocalDate.from(date);
			LocalDate firstday = localDate.with(fieldISO, 1);
			startdate = firstday.minusDays(14);
			//查询天数
			dayCount = 28;
		}

		int thresholdCount = 8;
		Semaphore semaphore = new Semaphore(thresholdCount);
		CountDownLatch countDownLatch = new CountDownLatch(dayCount);

		for (int i = 0; i < dayCount; i++) {
			LocalDate indexDate = startdate.plusDays(i);
			HomeworkStatusThreadV2 homeworkStatusJob = new HomeworkStatusThreadV2(indexDate, vo, resultMap, semaphore, countDownLatch);
			new Thread(homeworkStatusJob).start();
		}
		countDownLatch.await();
		return new R<Map<LocalDate, HomeworkDashboardRespVO>>(resultMap);
	}

	@Override
	public R getHomeworkHelpMonth(String startDate, String studentId, boolean isStudent) {

		Map<LocalDate, String> resultMap = MapUtil.newHashMap();

		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(startDate, dateTimeFormatter);

		if ("-1".equals(studentId)) {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			studentId = studentFeignService.getStudentId(memberId);
		}

		Month month = date.getMonth();

		int monthValue = date.withMonth(month.getValue()).lengthOfMonth();

		//每月开始日期
		LocalDate startdate = date.with(TemporalAdjusters.firstDayOfMonth());

		for (int i = 0; i < monthValue; i++) {

			List<MidoHomeworkMainVO> finalList = new ArrayList<>();

			if (isStudent) {

//				List<String> teacherIdList = teacherFeignService.getTeacherIdsByStudentId(studentId);
//
//				List<OrgRelationshipUnlinkLog> unlinkTeacherLogs = teacherFeignService.getUniqueTeacherUnlinkLog(studentId);
//
//				for (OrgRelationshipUnlinkLog log : unlinkTeacherLogs) {
//					for (String teacherId : teacherIdList) {
//						if (!teacherId.equals(log.getTeacherId())) {
//							List<MidoHomeworkMainVO> tmpList = mainMapper.getHomework(
//									studentId, startdate.plusDays(i).toString(), null, "0", log.getTeacherId());
//							finalList.addAll(tmpList);
//						}
//					}
//				}
//
//				if (teacherIdList != null && teacherIdList.size() != 0) {
//					for (int j = 0; j < teacherIdList.size(); j++) {
//						String teacherId = teacherIdList.get(j);
//						List<MidoHomeworkMainVO> tmpList = mainMapper.getHomework(
//								studentId, startDate, null, "0", teacherId);
//						finalList.addAll(tmpList);
//					}
//				}

				List<MidoHomeworkMainVO> tmpList = mainMapper.getHomework(
						studentId, startDate, null, "0", null);

				if (CollectionUtils.isNotEmpty(tmpList)) {
					finalList.addAll(tmpList);
				}

			} else {
				List<MidoHomeworkMainVO> tmpList = mainMapper.getHomework(
						studentId, startDate, null, "0",
						teacherFeignService.getCurTeacherIdByStu(studentId));

				if (CollectionUtils.isNotEmpty(tmpList)) {
					finalList.addAll(tmpList);
				}

			}

			// 筛选有辅导的作业
			resultMap.put(startdate.plusDays(i),
					finalList.stream().anyMatch(x -> "1".equals(x.getIsHelp())) ? "1" : "0");
		}
		return new R(resultMap);

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<Integer> updateDing(String startDate) {
		int totalUpdate = 0;

		try {
			//member_id
			String memberId = SecurityUtils.getMember().getId();
			//根据member_id获取学生ID
			String studentId = studentFeignService.getStudentId(memberId);

			if ("0".equals(studentId)) {
				return new R(CommonConstants.SUCCESS, "", totalUpdate);
			}

			List<String> teacherIdList = teacherFeignService.getTeacherIdsByStudentId(studentId);

			if (teacherIdList == null || teacherIdList.size() == 0) {
				throw new BusinessException("学生未绑定老师，学生自留作业无提醒!");
			}

			totalUpdate = 0;
			for (int i = 0; i < teacherIdList.size(); i++) {
				int temp = mainMapper.updateDing(studentId, startDate, teacherIdList.get(i));
				totalUpdate += temp;
			}
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
			throw e;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return new R(CommonConstants.FAIL, "更新DING失败！", false);
		}

		//取消提醒
		return new R(totalUpdate);
	}

	@Override
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Boolean deleteHomeworkBatch(List<String> idList) {
		Boolean result;
		try {
			result = mainMapper.deleteBatchIds(idList) > 0 ? true : false;

			for (String id : idList) {
				MidoHomeworkMain entity =
						mainMapper.selectOne(
								new QueryWrapper<MidoHomeworkMain>().eq("id", Long.valueOf(id)));

				if (entity == null) {
					continue;
				}

				dealWithAssignLimit(entity);
			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return false;
		}

		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
	public Boolean deleteHomeworkBatchV2(Map<String, Object> reqList) {

		List<String> groupIdsList = (List) reqList.get("groupIds");

		String startDate = (String) reqList.get("startDate");

		for (String groupId : groupIdsList) {

			String[] split = groupId.split("_");

			mainMapper.deleteHomeworkBatchV2(split[0], split[1], startDate);

		}
		return true;
	}


	/**
	 * 获取教师姓名
	 *
	 * @param teacherId
	 * @return java.lang.String
	 * @author nianhua.jiang
	 * @date 2020/7/3 10:59
	 */
	@Override
	public String getTeacherName(String teacherId) {
		return mainMapper.getTeacherName(teacherId);
	}

	/**
	 * 删除作业
	 *
	 * @param id
	 * @return java.lang.Boolean
	 * @author nianhua.jiang
	 * @date 2020/7/3 16:37
	 */
	@Override
	@Transactional(rollbackFor = Exception.class, timeout = 36000, propagation = Propagation.REQUIRED)
	public Boolean deleteHomework(String id) {
		try {
			MidoHomeworkMain entity =
					mainMapper.selectOne(
							new QueryWrapper<MidoHomeworkMain>().eq("id", Long.valueOf(id)));

			if (entity == null) {
				return false;
			}

			//删除作业主表
			mainMapper.deleteById(id);
			//删除作业完成情况表
			complateMapper.delete(new QueryWrapper<MidoHomeworkComplate>().eq(MidoHomeworkComplate.COL_HOMEWORK_ID, id));
			//删除作业评论表
			commentMapper.delete(new QueryWrapper<MidoHomeworkComment>().eq(MidoHomeworkComment.COL_HOMEWORK_ID, id));
			//处理assignLimit数量
			dealWithAssignLimit(entity);

		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return false;
		}

		return true;
	}

	/**
	 * 获取当天的作业完成情况
	 *
	 * @param startDate
	 * @param studentId
	 * @return java.util.List<com.shycloud.mido.homework.api.entity.MidoHomeworkMain>
	 * @author nianhua.jiang
	 * @date 2020/7/3 18:32
	 */
	@Override
	public List<String> getHomeWorkStatus(LocalDate startDate, String studentId, String teacherId) {
		return mainMapper.getHomeWorkStatus(startDate, studentId, teacherId);
	}

	@Override
	public List<String> getHomeWorkDing(LocalDate startDate, String studentId, String teacherId) {
		return mainMapper.getHomeWorkDing(startDate, studentId, teacherId);
	}

	@Override
	public List<String> getHomeWorkStatusByStu(LocalDate startDate, String studentId) {
		return mainMapper.getHomeWorkStatusByStu(startDate, studentId);
	}

	@Override
	public List<String> getHomeWorkDingByStu(LocalDate startDate, String studentId) {
		return mainMapper.getHomeWorkDingByStu(startDate, studentId);
	}

	/**
	 * 获取筛选曲目列表
	 *
	 * @param studentId
	 * @param startDate
	 * @return java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
	 * @author nianhua.jiang
	 * @date 2020/7/8 9:41
	 */
	@Override
	public List<MusicNameVO> getHomeworkMusicList(String studentId, String startDate,
			String teacherId) {
		return mainMapper.getHomeworkMusicList(studentId, startDate, teacherId);
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	protected void consumeAssign(AssignDto assignDto) {

		Integer curConsume = 0;
		Integer nextConsume = 0;
		Date startDate;
		Date endDate;
		String startDateStr;
		String endDateStr;
		Integer startMonth = 0;
		Integer curMonth = 0;

		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		Integer periodLen = propertiesConfig.getPeriodLenOfEachYear();
		Date lastDayOfStartDateMonth = DateUtil.getLastDayOfMonth(0);
		Integer dayAssignCount =
				assignDto.getTypeOneNum() + assignDto.getTypeTwoNum() + assignDto.getTypeThreeNum();
		Boolean noNeedGetNextAssign = false;

		try {
			startDateStr = formatter.format(assignDto.getStartDate());
			endDateStr = formatter.format(assignDto.getEndDate());
			startDate = formatter.parse(startDateStr);
			endDate = formatter.parse(endDateStr);

			startMonth = Integer.valueOf(startDateStr.split("-")[1]);
			curMonth = Integer.valueOf(formatter.format(new Date()).split("-")[1]);

			//若periodLen为3，则三个月的对应的余数为1, 2, 0
			//若periodLen为2，则三个月的对应的余数为1, 0
			//startMonth >= curMonth
			Integer remainder = startMonth % periodLen;
			if (remainder == 0 && startMonth == curMonth) {
				curConsume = lastDayOfStartDateMonth.compareTo(endDate) <= 0 ?
						(DateUtil.getDaysDiff(startDate, lastDayOfStartDateMonth) + 1)
								* dayAssignCount
						: (DateUtil.getDaysDiff(startDate, endDate) + 1) * dayAssignCount;
			} else if (remainder != 0) {
				int monthDiff = startMonth - curMonth;
				for (int i = 0; i < periodLen - remainder + 1; i++) {
					Date lastDayOfMon = DateUtil.getLastDayOfMonth(i + monthDiff);

					if (lastDayOfMon.compareTo(endDate) <= 0) {
						curConsume += (DateUtil.getDaysDiff(startDate, lastDayOfMon) + 1) * dayAssignCount;
					} else {
						curConsume += (DateUtil.getDaysDiff(startDate, endDate) + 1) * dayAssignCount;
						noNeedGetNextAssign = true;
						break;
					}
				}
			}

			if (!noNeedGetNextAssign) {
				int monthDiff = startMonth - curMonth;
				int monthIdx = (remainder == 0 ? 1 : periodLen - remainder + 1) + monthDiff;

				for (int i = 0; i < periodLen; i++) {
					Date lastDayOfMon = DateUtil.getLastDayOfMonth(monthIdx + i);
					Date nextPeriodStartDay = DateUtil.getFirstDayOfMonth(monthIdx + i);

					if (endDate.compareTo(nextPeriodStartDay) <= 0) {
						break;
					}

					if (lastDayOfMon.compareTo(endDate) <= 0) {
						nextConsume += (DateUtil.getDaysDiff(nextPeriodStartDay, lastDayOfMon) + 1) * dayAssignCount;
					} else {
						nextConsume += (DateUtil.getDaysDiff(nextPeriodStartDay, endDate) + 1) * dayAssignCount;
						break;
					}
				}
			}

//			if (assignDto.getStudentList() != null) {
//				for (String studentId : assignDto.getStudentList()) {
//					if (curConsume != 0 || nextConsume != 0) {
//						//先检查是否可以扣除，若扣除完为负数，则不给扣除
//						if (!checkAssignRestrictRule(studentId, curConsume, nextConsume)) {
//							throw new BusinessException("该学生作业分配数量已超最大限制, 若想留更多作业请联系客服!");
//						}
//
//						//扣除对应可被布置作业数量
//						studentFeignService.consumeAssignBal(studentId, curConsume, nextConsume);
//					}
//				}
//			} else if (assignDto.getStudentId() != null) {
//				if (curConsume != 0 || nextConsume != 0) {
//					//先检查是否可以扣除，若扣除完为负数，则不给扣除
//					if (!checkAssignRestrictRule(assignDto.getStudentId(), curConsume,
//							nextConsume)) {
//						throw new BusinessException("该学生作业分配数量已超最大限制, 若想留更多作业请联系客服!");
//					}
//
//					//扣除对应可被布置作业数量
//					studentFeignService
//							.consumeAssignBal(assignDto.getStudentId(), curConsume, nextConsume);
//				}
//			}
		} catch (ParseException e) {
			log.error(e.getMessage(), e);
			log.error("解析时间字符串错误!");
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			throw e;
		}
	}

	private boolean checkAssignRestrictRule(String studentId, Integer curConsume,
			Integer nextConsume) {
		Map assignBalMap = studentFeignService.getStudentAssignBal(studentId);

		if (assignBalMap == null) {
			return false;
		}

		Object curAssignBal = assignBalMap.get("curAssignBal");
		Object nextAssignBal = assignBalMap.get("nextAssignBal");

		if (curAssignBal == null) {
			return false;
		}
		if (nextAssignBal == null) {
			return false;
		}

		if ((Integer) curAssignBal < 0 || (Integer) curAssignBal - curConsume < 0) {
			return false;
		}
		if ((Integer) nextAssignBal < 0 || (Integer) nextAssignBal - nextConsume < 0) {
			return false;
		}

		return true;
	}

	@Deprecated
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	protected void consumeAssignOld(AssignDto assignDto) throws Exception {
		Integer curConsume = 0;
		Integer nextConsume = 0;
		SimpleDateFormat formatter = new SimpleDateFormat("MM-dd");
		Date startDate = null;
		Date endDate = null;
		Date periodStartDate = null;
		Date periodEndDate = null;
		Integer dayAssignQuantities =
				assignDto.getTypeOneNum() + assignDto.getTypeTwoNum() + assignDto.getTypeThreeNum();
		boolean nextConsumePeriod = false;

		try {
			startDate = formatter.parse(formatter.format(assignDto.getStartDate()));
			endDate = formatter.parse(formatter.format(assignDto.getEndDate()));
		} catch (ParseException e) {
			log.error(e.getMessage(), e);
			log.error("解析时间字符串错误!");
		}

		for (AssignLimitPeriodEnum periodEnum : AssignLimitPeriodEnum.values()) {
			String periodStartDateStr = periodEnum.getStartDate();
			String periodEndDateStr = periodEnum.getEndDate();

			try {
				periodStartDate = formatter.parse(periodStartDateStr);
				periodEndDate = formatter.parse(periodEndDateStr);
			} catch (ParseException e) {
				log.error(e.getMessage(), e);
				log.error("解析时间字符串错误!");
			}

			if (nextConsumePeriod) {
				Instant inst3 = Instant.ofEpochMilli(periodStartDate.getTime());
				Instant inst4 = Instant.ofEpochMilli(endDate.getTime());
				Long seconds2 = Duration.between(inst3, inst4).getSeconds();
				Long days2 = seconds2 / (24 * 60 * 60);
				nextConsume = days2.intValue() * dayAssignQuantities;
				break;
			}

			//说明startDate在此时间段
			if (periodStartDate.compareTo(startDate) <= 0
					&& startDate.compareTo(periodEndDate) <= 0) {
				Instant inst1 = Instant.ofEpochMilli(startDate.getTime());
				Instant inst2 = Instant.ofEpochMilli(periodEndDate.getTime());
				Long seconds = Duration.between(inst1, inst2).getSeconds();
				Long days = seconds / (24 * 60 * 60);
				curConsume = days.intValue() * dayAssignQuantities;

				//此处判断条件不对
				if (endDate.compareTo(periodEndDate) <= 0) {
					break;
				}
				nextConsumePeriod = true;
			}
		}

		//说明是最后一个period匹配到了curPeriod，则下一个nextPeriod是新循环的第一个period，然后break
		if (curConsume == 0) {
			for (AssignLimitPeriodEnum periodEnum : AssignLimitPeriodEnum.values()) {
				Instant inst1 = Instant.ofEpochMilli(startDate.getTime());
				Instant inst2 = Instant.ofEpochMilli(periodEndDate.getTime());
				Long seconds = Duration.between(inst1, inst2).getSeconds();
				Long days = seconds / (24 * 60 * 60);
				curConsume = days.intValue() * dayAssignQuantities;
				break;
			}
		}

		if (assignDto.getStudentList() != null) {
			for (String studentId : assignDto.getStudentList()) {
				studentFeignService.consumeAssignBal(studentId, curConsume, nextConsume);
			}
		} else if (assignDto.getStudentId() != null) {
			studentFeignService.consumeAssignBal(assignDto.getStudentId(), curConsume, nextConsume);
		}
	}

	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	protected void dealWithAssignLimit(MidoHomeworkMain entity) throws Exception {
		SimpleDateFormat formatter = new SimpleDateFormat("MM-dd");
		Date periodStartDate = null;
		Date periodEndDate = null;
		Date homeworkDate = entity.getStartDate();

		for (AssignLimitPeriodEnum periodEnum : AssignLimitPeriodEnum.values()) {
			String periodStartDateStr = periodEnum.getStartDate();
			String periodEndDateStr = periodEnum.getEndDate();

			try {
				periodStartDate = formatter.parse(periodStartDateStr);
				periodEndDate = formatter.parse(periodEndDateStr);
			} catch (ParseException e) {
				log.error(e.getMessage(), e);
				log.error("解析时间字符串错误!");
			}

			if (periodStartDate.compareTo(homeworkDate) <= 0
					&& homeworkDate.compareTo(periodEndDate) <= 0) {
				studentFeignService.consumeAssignBal(entity.getStudentId(), -1, 0);
			} else if (periodStartDate.compareTo(homeworkDate) <= 0
					&& homeworkDate.compareTo(periodEndDate) <= 0) {
				studentFeignService.consumeAssignBal(entity.getStudentId(), 0, -1);
			}
		}
	}

	/**
	 * 根据 studentId 获取对应的极光推送 regId
	 *
	 * @param studentId
	 * @return java.lang.String
	 * @author nianhua.jiang
	 * @date 2021/1/14 13:30
	 **/
	@Override
	public String getRegIdByStudentId(String studentId) {
		return mainMapper.getRegIdByStudentId(studentId);
	}

	/**
	 * 获取教师提醒学生要发送的推送信息
	 *
	 * @return java.util.Map<java.lang.String, java.lang.String>
	 * @author nianhua.jiang
	 * @date 2021/1/14 13:46
	 **/
	@Override
	public Map<String, String> getRemindStudentPushMessage() {
		return mainMapper.getRemindStudentPushMessage(1);
	}


	@Override
	public List<AtvActiveDetailItemVO> studentActiveDatailByComplate(AtvActiveDetailReqVO vo) {
		return mainMapper.studentActiveDatailByComplate(vo);
	}

	@Override
	public List<AtvActiveDetailItemVO> studentActiveDatailByHomework(AtvActiveDetailReqVO vo) {
		return mainMapper.studentActiveDatailByHomework(vo);
	}

	@Override
	public List<AtvScheduleVO> atvSchedule(AtvScheduleReqVO vo) {
		Date beginDatetime = vo.getBeginDatetime();//活动开始日
		Date endDatetime = vo.getEndDatetime();
		LocalDate beginDate = beginDatetime.toInstant().atZone(ZoneId.systemDefault())
				.toLocalDate();
		LocalDate endDate = endDatetime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

		long days = ChronoUnit.DAYS.between(beginDate, LocalDate.now());
		if (days < 0) {
			days = 0;
		} else if (days >= 0) {
			days = days + 1L;
		}

		if (endDate.equals(LocalDate.now()) || LocalDate.now().isAfter(endDate)) {
			days = ChronoUnit.DAYS.between(beginDate, endDate) + 1L;
		}

		//获取活动人员详情
		String mainAtvId = vo.getId();

		List<AtvScheduleVO> atvStudentDetails = mainMapper.getAtvStudentDetail(mainAtvId);

		List<String> studentIds = atvStudentDetails.stream()
				.filter(item -> Objects.nonNull(item.getStudentId()))
				.map(AtvScheduleVO::getStudentId).collect(Collectors.toList());
		if ("1".equals(vo.getFlg())) {
			//查询登录人的studentId
			String memberId = SecurityUtils.getMember().getId();
			String studentId = mainMapper.getstudentIdByMemberId(memberId);
			studentIds = studentIds.stream().filter(x -> !studentId.equals(x))
					.collect(Collectors.toList());
			atvStudentDetails = atvStudentDetails.stream()
					.filter(item -> !StringUtils.equals(studentId, item.getStudentId()))
					.collect(Collectors.toList());
		}
		if (CollectionUtils.isEmpty(studentIds)) {
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				atvStudentDetail.setOkDays(0);
				atvStudentDetail.setPlaySeconds(0);
				atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
			}
			return atvStudentDetails;
		}

		//查询已完成天数
		List<AtvScheduleVO> okDays = mainMapper
				.getOkDays(vo.getBeginDatetime(), vo.getEndDatetime(), studentIds);
		if (CollectionUtils.isEmpty(okDays)) {
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				atvStudentDetail.setOkDays(0);
				atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
			}
		} else {
			//是否全完成
			List<AtvScheduleVO> collect = okDays.stream().filter(item -> item.getDone() == 0)
					.collect(Collectors.toList());
			if (CollectionUtils.isEmpty(collect)) {
				for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
					atvStudentDetail.setOkDays(0);
					atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
				}
			}
			//分组转化 BY学生
			Map<String, Long> countMap = collect.stream().collect(
					Collectors.groupingBy(AtvScheduleVO::getStudentId, Collectors.counting()));
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				Long count = countMap.get(atvStudentDetail.getStudentId());
				if (count != null) {
					atvStudentDetail.setOkDays(Integer.parseInt(String.valueOf(count)));
					atvStudentDetail.setLackDays(
							Integer.valueOf(String.valueOf(days)) - atvStudentDetail.getOkDays());
				} else {
					atvStudentDetail.setOkDays(0);
					atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
				}
			}
		}

		//查询总练琴时长
		List<AtvScheduleVO> totalTimes = mainMapper
				.getTotalTimes(vo.getBeginDatetime(), vo.getEndDatetime(), studentIds);
		if (CollectionUtils.isEmpty(totalTimes)) {
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				atvStudentDetail.setPlaySeconds(0);
			}
		} else {
			//分组装载

			Map<String, AtvScheduleVO> totalTimesGroup = totalTimes.stream().collect(
					Collectors.toMap(AtvScheduleVO::getStudentId, item -> item, (k1, k2) -> k1));

			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				AtvScheduleVO totalDetail = totalTimesGroup.get(atvStudentDetail.getStudentId());
				if (totalDetail != null) {
					atvStudentDetail.setPlaySeconds(totalDetail.getPlaySeconds());
				}
			}
		}
		return atvStudentDetails;
	}

	@Override
	public List<AtvScheduleVO> atvScheduleDetail(AtvScheduleReqVO vo) {

		//活动开始日
		Date beginDatetime = vo.getBeginDatetime();
		Date endDatetime = vo.getEndDatetime();
		LocalDate beginDate = beginDatetime.toInstant().atZone(ZoneId.systemDefault())
				.toLocalDate();
		LocalDate endDate = endDatetime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

		long days = ChronoUnit.DAYS.between(beginDate, LocalDate.now());
		if (days < 0) {
			days = 0;
		} else if (days >= 0) {
			days = days + 1L;
		}

		if (endDate.equals(LocalDate.now()) || LocalDate.now().isAfter(endDate)) {
			days = ChronoUnit.DAYS.between(beginDate, endDate) + 1L;
		}

		//获取活动人员详情
		String mainAtvId = vo.getId();

		List<AtvScheduleVO> atvStudentDetails = mainMapper.getAtvStudentDetail(mainAtvId);

		List<String> studentIds = atvStudentDetails.stream()
				.filter(item -> Objects.nonNull(item.getStudentId()))
				.map(AtvScheduleVO::getStudentId).collect(Collectors.toList());
		//TODO 2021-06-30 日修正：APP活动进度接口不是自己的学生隐藏信息 START========//
		//创建迭代器筛选此教师下面的学生
		for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
			if (!vo.getStudentIds().contains(atvStudentDetail.getStudentId())) {
				atvStudentDetail.setIsMyStudent("0");
			} else {
				atvStudentDetail.setIsMyStudent("1");
			}
		}
		//TODO 2021-06-30 日修正：APP活动进度接口不是自己的学生隐藏信息 E-N-D========//

		//查询已完成天数
		List<AtvScheduleVO> okDays = mainMapper
				.getOkDays(vo.getBeginDatetime(), vo.getEndDatetime(), studentIds);
		if (CollectionUtils.isEmpty(okDays)) {
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				atvStudentDetail.setOkDays(0);
				atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
			}
		} else {
			//当天完成作业集合
			List<AtvScheduleVO> okDayList = okDays.stream().filter(item -> item.getDone() == 0)
					.collect(Collectors.toList());
			if (CollectionUtils.isEmpty(okDayList)) {
				for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
					atvStudentDetail.setOkDays(0);
					atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
				}
			}
			//挑战赛天数
			long activityDays = ChronoUnit.DAYS.between(beginDate, endDate);
			ArrayList<String> dateList = new ArrayList<>();

			Stream.iterate(beginDate, day -> {
				return day.plusDays(1);
			}).limit(activityDays + 1).forEach(item -> {
				dateList.add(item.toString());
			});
			//分组转化 BY学生
			Map<String, Long> countMap = okDayList.stream().collect(
					Collectors.groupingBy(AtvScheduleVO::getStudentId, Collectors.counting()));
			DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd");

			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				//先过滤学生,按照日期分组获取每一天的作业详情
				Map<String, AtvScheduleVO> homeworkMap = okDayList.stream()
						.filter(item -> StringUtils
								.equals(item.getStudentId(), atvStudentDetail.getStudentId()))
						.collect(Collectors.toMap(data -> {
							return data.getStartDate().toInstant().atZone(ZoneId.systemDefault())
									.toLocalDate().format(pattern);
						}, item -> item, (k1, k2) -> k1));

				//统计每个学生每天打卡详细
				List<AtvActiveDetailItemVO> atvActiveDetailItemList = new ArrayList<>();
				for (int i = 0; i < dateList.size(); i++) {
					AtvScheduleVO okItem = homeworkMap.get(dateList.get(i));
					AtvActiveDetailItemVO detailItem = new AtvActiveDetailItemVO();
					detailItem.setIndex(1 + i);
					detailItem.setActionDate(dateList.get(i));
					if (Objects.nonNull(okItem) && okItem.getStudentId()
							.equals(atvStudentDetail.getStudentId())) {
						detailItem.setActionFalg("1");
					}
					atvActiveDetailItemList.add(detailItem);
				}
				atvStudentDetail.setAtvActiveDetailItemList(atvActiveDetailItemList);

				//学生打卡汇总
				Long count = countMap.get(atvStudentDetail.getStudentId());
				if (count != null) {
					atvStudentDetail.setOkDays(Integer.parseInt(String.valueOf(count)));
					atvStudentDetail.setLackDays(
							Integer.valueOf(String.valueOf(days)) - atvStudentDetail.getOkDays());
				} else {
					atvStudentDetail.setOkDays(0);
					atvStudentDetail.setLackDays(Integer.valueOf(String.valueOf(days)));
				}
			}
		}

		//查询总练琴时长
		List<AtvScheduleVO> totalTimes = mainMapper
				.getTotalTimes(vo.getBeginDatetime(), vo.getEndDatetime(), studentIds);
		if (CollectionUtils.isEmpty(totalTimes)) {
			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				atvStudentDetail.setPlaySeconds(0);
			}
		} else {
			//分组装载

			Map<String, AtvScheduleVO> totalTimesGroup = totalTimes.stream().collect(
					Collectors.toMap(AtvScheduleVO::getStudentId, item -> item, (k1, k2) -> k1));

			for (AtvScheduleVO atvStudentDetail : atvStudentDetails) {
				AtvScheduleVO totalDetail = totalTimesGroup.get(atvStudentDetail.getStudentId());
				if (totalDetail != null) {
					atvStudentDetail.setPlaySeconds(totalDetail.getPlaySeconds());
				}
			}
		}
		return atvStudentDetails;
	}

}
